package utils.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;

import kb.ABox;
import kb.DescriptionLogicsKB;
import kb.TBox;

import utils.parser.Parser;
import utils.exception.SyntaxParsingException;


import entities.Assertion;
import entities.Axiom;
import entities.vocabulary.Display;
import entities.vocabulary.KBVocabulary;

public class KBAccess {
	

	private KBAccess(){	
		
	}
	
	
	//////////TBox functions
	public static TBox getTBox(String fileName) throws IOException{
		return getTBox(fileName, false);
	}
	
	
	
	public static TBox getTBox(String fileName, boolean prime) throws IOException{
		BufferedReader in = new BufferedReader(new FileReader(fileName));
		return getTBox(in, prime);
	}
	
	public static TBox getTBox(BufferedReader in) throws IOException{
		return getTBox(in, false);
	}
	
	public static TBox getTBox(BufferedReader in, boolean prime) throws IOException{
		//PrintStream out = new PrintStream(System.out, true, "UTF-8");

		if (in == null) {
			return null;
		}
		HashSet<Axiom> axs = processAxiomFile(in, prime);
		return newTBoxInstance(axs);
	}
	//build a Tbox from the given axioms
	public static TBox newTBoxInstance(HashSet<Axiom> ax){
		TBox tb = new TBox();
		for(Axiom x:ax){
			tb.mapAxiom(x);
		}
		return tb;
	}



	
	//return a  set of axioms
	public static HashSet<Axiom> processAxiomFile(String filename) throws IOException{
		return processAxiomFile(filename, false);
	}
	
	private static HashSet<Axiom> processAxiomFile(String filename, boolean prime) throws IOException {
		BufferedReader in = new BufferedReader(new FileReader(filename));
		return processAxiomFile(in, prime);
	}
	
	private static HashSet<Axiom> processAxiomFile(BufferedReader br, boolean prime) throws IOException{
		HashSet<Axiom> axs = new HashSet<Axiom>();
		try{
        String strLine;
        while ((strLine = br.readLine()) != null)   {
            // no empty lines as input
        	if (strLine == null || strLine.trim().equals("")
        			||strLine.startsWith(Display.COMMENTS)){
        		continue;
        	}
			Axiom ax = null;
			try {
				ax = Parser.parseAxioms(Parser.getListOfTokensFromTokenizer(strLine));
			} catch (SyntaxParsingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			axs.add(ax);
//			if(verbose){
//				//print axioms
//				String s = ax.toString();
//				System.out.println(s +"\n--------");
//			}
			if (prime) {
				ax = ax.getPrimeCopy();
				axs.add(ax);
//				if(verbose){
//					//print axioms
//					String s = ax.toString();
//					System.out.println(s +"\n--------");
//				}
			}
			
          }
		}catch(IOException e){
			e.printStackTrace();
			throw e;
		}
		return axs;
	}
	

	
	//////////ABox Functions
	
	//get assertions and build an ABox from the assertions
	public static ABox newABoxInstance(HashSet<Assertion> ax){
		ABox ab = new ABox();
		//index all assertions here
		for(Assertion a:ax){
			ab.insertAssertions(a);
		}
		return ab;
	}
	
	//build an ABox from one assertion, useful for testing assertion entailment
	public static ABox newABoxInstance(Assertion a){
		ABox ab = new ABox();
		ab.insertAssertions(a);
		return ab;
	}
	
	
	public static ABox getABox(String fileName) throws IOException{
		BufferedReader in = new BufferedReader(new FileReader(fileName));
		return getABox(in, false);
	}
	
	public static ABox getABox(String fileName, boolean prime) throws IOException{
		BufferedReader in = new BufferedReader(new FileReader(fileName));
		return getABox(in, prime);
	}
	
	private static ABox getABox(BufferedReader in, boolean prime) throws IOException{
		if (in == null) {
			return null;
		}
		HashSet<Assertion> axs = processAssertionFile(in, prime);
		ABox ab = KBAccess.newABoxInstance(axs);
		return ab;
	}
	
	//return a set of assertions to be checked for entailment
	public static HashSet<Assertion> getAssertionsToCheck(String file) throws IOException{
		BufferedReader in = new BufferedReader(new FileReader(file));
		return getAssertionsToCheck(in);
	}
	
	private static HashSet<Assertion> getAssertionsToCheck(BufferedReader br){
		HashSet<Assertion> axs = new HashSet<Assertion>();	
		try{
	        String strLine;
	        while ((strLine = br.readLine()) != null)   {
	            // no empty lines as input
	        	if (strLine == null || strLine.trim().equals("")
	        			||strLine.startsWith(Display.COMMENTS)){
	        		continue;
	        	}else if(strLine.startsWith(Display.QUERYSYMBOL)){
	        		strLine = strLine.substring(strLine.lastIndexOf(Display.QUERYSYMBOL)+1);
					Assertion ax = null;
					try {
						ax = Parser.parseAssertions(Parser.getListOfTokensFromTokenizer(strLine));
					} catch (SyntaxParsingException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					axs.add(ax);
	        	}
	          }
			}catch(IOException e){
				e.printStackTrace();
			}	
		if(axs.size() < 1){
			System.err.println("No assertions given to be checked.");
		}
		return axs;
	}
	
	public static HashSet<Assertion> processAssertionFile(BufferedReader br, boolean prime) throws IOException{
		HashSet<Assertion> axs = new HashSet<Assertion>();
		try{
        String strLine;
        while ((strLine = br.readLine()) != null){
            // no empty lines as input
        	if (strLine == null || strLine.trim().equals("")
        			||strLine.startsWith(Display.COMMENTS)){
        		continue;
        	}
			Assertion ax = null;
			try {
				ax = Parser.parseAssertions(Parser.getListOfTokensFromTokenizer(strLine));
			} catch (SyntaxParsingException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			axs.add(ax);
			if (prime) {
				ax = ax.getPrimeCopy();
				axs.add(ax);
			}
			
          }
		}catch(IOException e){
			e.printStackTrace();
			throw e;
		}
		return axs;
	}
	
	//both TBox and ABox are in the same file
	public static DescriptionLogicsKB processKBFile(BufferedReader br, boolean prime) throws IOException{
		TBox tb = new TBox();
		ABox ab = new ABox();
		int ca = 0, ra = 0, nax = 0;
		try{
			String strLine;
	        while ((strLine = br.readLine()) != null){
	            // no empty lines as input
	        	if (strLine == null || strLine.trim().equals("")
	        			||strLine.startsWith(Display.COMMENTS)){
	        		continue;
	        	}else if(strLine.startsWith(Display.QUERYSYMBOL)){
	        		//either a query file or assertion to be checked
	        		System.err.println("Query line or assertion check line found, ignored : "+strLine);
	        		continue;
	        	}else if(strLine.contains(KBVocabulary.EQAXIOM) || strLine.contains(KBVocabulary.IMPLIES)){
	        		Axiom ax = null;
					try {
						ax = Parser.parseAxioms(Parser.getListOfTokensFromTokenizer(strLine));
					} catch (SyntaxParsingException e) {
						e.printStackTrace();
					}
					nax++;
					tb.insertTg(ax); 
					if (prime) {
						ax = ax.getPrimeCopy();
						tb.insertTg(ax);
					}
	        	}else if(strLine.contains(KBVocabulary.CONASSERT) || strLine.contains(KBVocabulary.ROLEASSERT)){
	        		Assertion ast = null;
					try {
						ast = Parser.parseAssertions(Parser.getListOfTokensFromTokenizer(strLine));
					} catch (SyntaxParsingException e) {
						e.printStackTrace();
					}
					if(strLine.contains(KBVocabulary.CONASSERT)){
						ca ++;
					}else ra++;
	        		ab.insertAssertions(ast);
	        		if (prime) {
						ast = ast.getPrimeCopy();
						ab.insertAssertions(ast);
					}
	        	}else{
	        		System.err.println("Unknown line in the file, ignored: "+strLine);
	        		continue;
	        	}
	          }
		}catch(IOException e){
			e.printStackTrace();
			throw e;
		}
		tb.setNumAx(nax);
		ab.setNums(ca, ra);
		return DescriptionLogicsKB.newKBInstance(tb, ab);
	}
	
	public static void writeOutKBFile(String f, String s){
		FileWriter fstream = null;
	    BufferedWriter out = null;
	    File file = new File(f);
		try {
			fstream = new FileWriter(file, false);
	        out = new BufferedWriter(fstream);
			out.write(s);
			out.newLine();
		} catch (IOException e) {
			System.err.println("KB file cannot be generated.");
			e.printStackTrace();
		}finally{
			try {
				fstream.flush();
				//fstream.close();
				out.flush();
				out.close();
			} catch (IOException e) {
				//System.out.println("file loc: "+f);
				e.printStackTrace();
			}
		}

	}
	

}
